﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using l1cs.server.server.datatables;

namespace l1cs.server.model.map
{
    class CachedMapReader : MapReader
    {
        /// <summary>マップディレクトリ</summary>
        private const String MAP_DIR = "./maps/";

        /// <summary>キャッシングするマップホルダー</summary>
        private const String CACHE_DIR = "./data/mapcache/";

        /// <summary>
        /// 指定のマップ番号のテキストマップをキャッシュマップに変更する
        /// </summary>
        /// <param name="mapId">マップ番号</param>
        /// <returns><see cref="L1V1Map"/></returns>
        private L1V1Map cacheMap( int mapId )
        {
            if ( !System.IO.Directory.Exists( CACHE_DIR ) )
            {
                System.IO.Directory.CreateDirectory( CACHE_DIR );
            }

            L1V1Map map = (L1V1Map)new TextMapReader().read( mapId );

            using ( BinaryWriter bout = new BinaryWriter( File.OpenWrite( CACHE_DIR + mapId + ".map" ) ) )
            {
                bout.Write( (int)map.getId() );
                bout.Write( (int)map.getX() );
                bout.Write( (int)map.getY() );
                bout.Write( (int)map.getWidth() );
                bout.Write( (int)map.getHeight() );

                byte[,] tiles = map.getRawTiles();
                for ( int i = 0; i < tiles.GetUpperBound( 0 ); i++ )
                {
                    for ( int j = 0; j < tiles.GetUpperBound( 1 ); j++ )
                    {
                        bout.Write( tiles[i, j] );
                    }
                }
            }

            return map;
        }

        /// <summary>
        /// 指定のマップ番号のキャッシュマップを読み込む.
        /// </summary>
        /// <param name="mapId">マップ番号</param>
        /// <returns><see cref="L1Map"/>L1Mapオブジェクト</returns>
        override
        public L1Map read( int mapId )
        {
            if ( !File.Exists( CACHE_DIR + mapId + ".map" ) )
            {
                return cacheMap( mapId );
            }

            int id;
            int xLoc;
            int yLoc;
            int width;
            int height;
            byte[,] tiles;
            using ( BinaryReader bin = new BinaryReader( File.OpenRead( CACHE_DIR + mapId + ".map" ) ) )
            {
                id = bin.ReadInt32();
                if ( mapId != id )
                {
                    return null;
                }

                xLoc = bin.ReadInt32();
                yLoc = bin.ReadInt32();
                width = bin.ReadInt32();
                height = bin.ReadInt32();

                tiles = new byte[width, height];
                for ( int i = 0; i < width; i++ )
                {
                    for ( int j = 0; j < height; j++ )
                    {
                        tiles[i, j] = bin.ReadByte();
                    }
                }
            }
            L1V1Map map = new L1V1Map( id, tiles, xLoc, yLoc,
                    MapsTable.getInstance().isUnderwater( mapId ),
                    MapsTable.getInstance().isMarkable( mapId ),
                    MapsTable.getInstance().isTeleportable( mapId ),
                    MapsTable.getInstance().isEscapable( mapId ),
                    MapsTable.getInstance().isUseResurrection( mapId ),
                    MapsTable.getInstance().isUsePainwand( mapId ),
                    MapsTable.getInstance().isEnabledDeathPenalty( mapId ),
                    MapsTable.getInstance().isTakePets( mapId ),
                    MapsTable.getInstance().isRecallPets( mapId ),
                    MapsTable.getInstance().isUsableItem( mapId ),
                    MapsTable.getInstance().isUsableSkill( mapId ) );
            return map;
        }

        /// <summary>
        /// 全てのテキストマップを読み込む
        /// </summary>
        /// <returns><see cref="L1Map">List<L1Map></see></returns>
        override
        public Dictionary<int, L1Map> read()
        {
            List<int> ids = new List<int>();
            int maxid = 0;
            string[] files = Directory.GetFiles( MAP_DIR, "*.txt", SearchOption.AllDirectories );
            foreach ( String fileName in files )
            {
                if ( !File.Exists( fileName ) )
                {
                    continue;
                }
                int id = 0;
                String idStr = Path.GetFileNameWithoutExtension( fileName );
                int.TryParse( idStr, out id );
                ids.Add( id );
                if ( maxid < id )
                {
                    maxid = id;
                }
            }

            Dictionary<int, L1Map> maps = new Dictionary<int, L1Map>( ids.Count );
            foreach ( int id in ids )
            {
                maps[id] = read( id );
            }
            return maps;
        }
    }
}
